using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using ProceduralGolf.generation;
using ProceduralGolf.generation.tests;

using JigLibX.Physics;
using JigLibX.Collision;
using System.Threading;

namespace ProceduralGolf
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class ProceduralGolf : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        // physics
        const float stepSize = 1.0f / 100.0f;
        const float simulationSpeed = 2.0f;
        double phase;

        GameManager gameManager;
        readonly int nHoles;
        int holeCounter;
        GolfCourse golfCourse;

        public LoadingScreen LoadingScreen { get { return loadingScreen; } }
        LoadingScreen loadingScreen;
        volatile bool loading = false;

#if !XBOX
        KeyboardState prevKeyboardState = Keyboard.GetState();
#endif
        GamePadState prevGamepadState = GamePad.GetState(PlayerIndex.One);

        bool wireframe = false;

        public ProceduralGolf()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferHeight = Configuration.Config.SettingGroups["Video"].Settings["Height"].GetValueAsInt();
            graphics.PreferredBackBufferWidth = Configuration.Config.SettingGroups["Video"].Settings["Width"].GetValueAsInt();
            if (Configuration.Config.SettingGroups["Video"].Settings["Fullscreen"].GetValueAsBool())
            {
                graphics.ToggleFullScreen();
            }
            graphics.ApplyChanges();

            Content.RootDirectory = "Content";
            if (Configuration.Config.SettingGroups["Video"].Settings["Fps"].GetValueAsBool())
            {
                Components.Add(new FrameRateCounter(this));
            }
            nHoles = Configuration.Config.SettingGroups["Game"].Settings["Holes"].GetValueAsInt();
        }

        protected override void Initialize()
        {
            InitializePhysics();
            base.Initialize();
        }

        protected void InitializePhysics()
        {
            PhysicsSystem physics = new PhysicsSystem();
            physics.SolverType = PhysicsSystem.Solver.Normal;
            physics.CollisionSystem = new CollisionSystemSAP();
            physics.EnableFreezing = true;

            phase = 0.0;
        }

        void LoadCourseThread()
        {
            InitializePhysics();
            ++holeCounter;
            if (holeCounter > nHoles)
                holeCounter = 1;

            if (holeCounter <= nHoles)
            {
                golfCourse = null;
                golfCourse = gameManager.GenerateCourse(holeCounter);
            }
            loading = false;
        }
        void LoadGolfCourse()
        {
            loading = true;
            golfCourse = null;
            GraphicsDevice.Reset();
            GC.Collect();
            loadingScreen.Message = "Golf Course";
            loadingScreen.Progress = 0.0f;
            Thread thread = new Thread(this.LoadCourseThread);
            thread.Start();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            loadingScreen = LoadingScreen.GetLoadingScreen(this);
            
            int minDist = Configuration.Config.SettingGroups["Course"].Settings["MinDistance"].GetValueAsInt();
            int maxDist = Configuration.Config.SettingGroups["Course"].Settings["MaxDistance"].GetValueAsInt();
            
            gameManager = new GameManager(this, nHoles, minDist, maxDist);
            holeCounter = 0;

            LoadGolfCourse();
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (loading)
            {
            }
            else
            {


#if !XBOX
                KeyboardState keyboardState = Keyboard.GetState();

                if (keyboardState.IsKeyDown(Keys.R) && prevKeyboardState.IsKeyUp(Keys.R))
                {
                    golfCourse.reset();
                }
                if (keyboardState.IsKeyDown(Keys.F) && prevKeyboardState.IsKeyUp(Keys.F))
                {
                    golfCourse.freeze();
                }

                if (keyboardState.IsKeyDown(Keys.Space) && prevKeyboardState.IsKeyUp(Keys.Space))
                {
                    wireframe = !wireframe;
                }
#endif
                GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);
                if (gamepadState.IsButtonDown(Buttons.X) && prevGamepadState.IsButtonUp(Buttons.X))
                {
                    wireframe = !wireframe;
                }

                //golfCourse.Update(gamepadState);

                // physics
                phase += (float)gameTime.ElapsedGameTime.TotalSeconds * simulationSpeed;
                while (phase > 0)
                {
                    PhysicsSystem.CurrentPhysicsSystem.Integrate(stepSize);
                    phase -= stepSize;
                }
#if !XBOX
                golfCourse.Update(keyboardState, gameTime);

#endif

                golfCourse.Update(gamepadState, gameTime);
#if !XBOX
                
                //if (golfCourse.Won)
                //{
                    if (keyboardState.IsKeyDown(Keys.Enter) && prevKeyboardState.IsKeyUp(Keys.Enter))
                        LoadGolfCourse();
                //}
#endif

                //if (golfCourse.Won)
                //{
                if (gamepadState.IsButtonDown(Buttons.Start) && prevGamepadState.IsButtonUp(Buttons.Start))
                    LoadGolfCourse();
                //} 

#if !XBOX
                    prevKeyboardState = keyboardState;
#endif
                prevGamepadState = gamepadState;
            }

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsMutex.GetMutex().WaitOne();
            GraphicsDevice.Clear(Color.CornflowerBlue);

            GraphicsDevice.RenderState.FillMode = wireframe ? FillMode.WireFrame : FillMode.Solid;
            //GraphicsDevice.RenderState.DepthBufferEnable = true;
            //GraphicsDevice.PresentationParameters.AutoDepthStencilFormat = DepthFormat.Depth24Stencil8Single;
            //GraphicsDevice.PresentationParameters.EnableAutoDepthStencil = true;

            if (loading)
            {
                loadingScreen.Draw();
            }
            else
            {
                golfCourse.Draw();
            }
            base.Draw(gameTime);
            GraphicsMutex.GetMutex().ReleaseMutex();
        }
    }
}
